A "strong semaphore" is one in which an unblocked thread is guaranteed
to get possession of the semaphore. In a "weak semaphore", an unblocked
thread must recheck the value of the semaphore variable before it can
take possession of the semaphore. A weak semaphore can allow one thread
to starve another tread.


First, here are "implementations" of strong and weak semaphores that
can take on negative values.

     STRONG                               WEAK
     ------                               ----

P(s)                                  P(s)
{                                     {
   s = s - 1;                            s = s - 1;
   if (s < 0)                            while (s < 0)
   {                                     {
      wait(s);                              wait(s);
   }                                     }
}                                     }



V(s)                                  V(s)
{                                     {
   s = s + 1;                            s = s + 1;
   if (s <= 0)                           if (s <= 0)
   {                                     {
      unblockOneThread(s);                  unblockOneThread(s);
   }                                     }
}                                     }




Second, here are "implementations" of strong and weak semaphores that
always have a non-negative value.

     STRONG                               WEAK
     ------                               ----

P(s)                                  P(s)
{                                     {
   if (s == 0)                           while (s == 0)
   {                                     {
      wait(s);                              wait(s);
   }                                     }
   s = s - 1;                            s = s - 1;
}                                     }



V(s)                                  V(s)
{                                     {
   s = s + 1;                            s = s + 1;
   unblockOneThread(s);                  unblockOneThread(s);
}                                     }


Notice that these implementations of V(s) are simplistic in that they
do not check if s has been incremented beyond the range that was declared
for s when the semaphore was constructed.





Here is an example where the semantics of weak vs. strong semaphores matters.

Suppose that semaphore1 is initially unsignaled and that threadA waits on
semaphore1 before threadB releases it. If the semaphore is a strong semaphore,
then the two threads will alternate their work. However, if the semaphore is
a weak semaphore, then threadB could starve threadA.


threadA                                threadB
{                                      {
   while(true)                            while(true)
   {                                      {
      wait(semaphore1);                      // work
      // work                                release(semaphore1);
      release(semaphore1);                   wait(semaphore1);
   }                                      }
}                                      }


Note that this code does not work properly if threadB releases semaphore1 before
threadA waits on it (even if the semaphore is a strong one).

This can be fixed by using two semaphores. Initially, both semaphores should
be unsignaled.


threadA                                threadB
{                                      {
   while(true)                            while(true)
   {                                      {
      wait(semaphore1);                      // work
      // work                                release(semaphore1);
      release(semaphore2);                   wait(semaphore2);
   }                                      }
}                                      }